﻿using Epic.Core;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Resources;

using Epic.HandyExtensions;

namespace Epic.ComponentServices
{
    partial class ExpandableAttributeProvider : TypeDescriptionProvider
    {
        //========//========//========//========
        // ExpandableAttributeTypeDescriptor 在此的目的有两个：
        // 1、确保 BasicPropertyOrderConverter, 否则无法实现属性排序
        // 2、利用 ExpandableAttributePropertyDescriptor 修饰属性, 将 UserFriendlyAttribute 翻译成其它东西
        //========//========//========//========
        private partial class ExpandableAttributeTypeDescriptor : CustomTypeDescriptor
        {
            private readonly ResourceManager mResMan;
            private readonly string mPrefix;
            public ExpandableAttributeTypeDescriptor(ICustomTypeDescriptor baseDescriptor, Type type)
                : base(baseDescriptor)
            {
                var lra = baseDescriptor.GetAttributes().OfType<LocalizationResourceAttribute>().FirstOrDefault();

                if (lra != null)
                {
                    mResMan = lra.GetResourceManager();
                    mPrefix = lra.Prefix;
                }

                if (mResMan != null)
                {
                    mPrefix = mPrefix ?? type.Name;
                }
                else
                {
                    mResMan = ResourceUtility.GetResourceManager(type.Assembly, type.FullName + "Resources");
                }

            }
            public override TypeConverter GetConverter()
            {
                var converter = base.GetConverter();
                if (converter is BasicPropertyOrderConverter)
                    return converter;
                return new MergedPropertyOrderConverter(base.GetConverter());
            }

            private PropertyDescriptorCollection EnchantPropertyAttributes(PropertyDescriptorCollection oldCollection)
            {
                PropertyDescriptorCollection result = oldCollection;
                var list = new List<PropertyDescriptor>(oldCollection.Count);

                foreach (var item in oldCollection.Cast<PropertyDescriptor>())
                {
                    var append = new List<Attribute>(2);

                    var dna = item.Attributes[typeof(DisplayNameAttribute)] as DisplayNameAttribute;
                    var ldna = dna as LocalizedDisplayNameAttribute;
                    if (ldna == null)
                    {
                        if (dna == null || dna.DisplayName.IsNullOrWhiteSpace())
                        {
                            append.Add(new PrefixedLocalizedDisplayNameAttribute(mResMan, mPrefix, item.Name));
                        }
                    }
                    else
                    {
                        var fix = false;

                        if (ldna.ResourceManager == null)
                        {
                            ldna.ResourceManager = mResMan;
                            fix = true;
                        }
                        if (ldna.DisplayNameKey.IsNullOrWhiteSpace())
                        {
                            ldna.DisplayNameKey = item.Name;
                            fix = true;
                        }

                        var pldna = ldna as PrefixedLocalizedDisplayNameAttribute;
                        if (pldna != null && pldna.Prefix == null)
                        {
                            pldna.Prefix = mPrefix;
                            fix = true;
                        }

                        if (fix)
                        {
                            append.Add(ldna);
                        }
                    }

                    var dsa = item.Attributes[typeof(DescriptionAttribute)] as DescriptionAttribute;
                    var ldsa = dsa as LocalizedDescriptionAttribute;
                    if (ldsa == null)
                    {
                        if (dsa == null || dsa.Description.IsNullOrWhiteSpace())
                        {
                            append.Add(new PrefixedLocalizedDescriptionAttribute(mResMan, mPrefix, item.Name));
                        }
                    }
                    else
                    {
                        var fix = false;

                        if (ldsa.ResourceManager == null)
                        {
                            ldsa.ResourceManager = mResMan;
                            fix = true;
                        }
                        if (ldsa.DescriptionKey.IsNullOrWhiteSpace())
                        {
                            ldsa.DescriptionKey = item.Name;
                            fix = true;
                        }

                        var pldsa = ldsa as PrefixedLocalizedDescriptionAttribute;
                        if (pldsa != null && pldsa.Prefix == null)
                        {
                            pldsa.Prefix = mPrefix;
                            fix = true;
                        }

                        if (fix)
                        {
                            append.Add(ldsa);
                        }
                    }

                    if (append.Count > 0)
                    {
                        list.Add(new ExpandableAttributePropertyDescriptor(item, append.ToArray()));

                        if (result != null)
                            result = null;
                    }
                    else
                    {
                        list.Add(item);
                    }
                }

                if (result == null)
                    result = new PropertyDescriptorCollection(list.ToArray(), true);

                return result;
            }
            public override PropertyDescriptorCollection GetProperties()
            {
                return EnchantPropertyAttributes(base.GetProperties());
            }
            public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
            {
                return EnchantPropertyAttributes(base.GetProperties(attributes));
            }
        }


    }
}
